package com.qw.soul.permission.checker;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.hardware.Camera;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.media.MediaRecorder;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.SystemClock;
import android.provider.CallLog;
import android.provider.ContactsContract;
import android.provider.Telephony;
import android.telephony.TelephonyManager;
import android.text.TextUtils;

import com.qw.soul.permission.PermissionActivityManager;
import com.qw.soul.permission.PermissionTools;
import com.qw.soul.permission.support.PermissionsPageManager;
import java.io.File;
import java.io.IOException;
import java.util.List;

/**
 * Created by ytf on 2019/07/06.
 * Description:
 */
public class AppExceptionChecker implements PermissionChecker
{

    private static boolean granted;
    private Context context;
    private String permission;
    private boolean isLocationRetured;

    AppExceptionChecker(Context context, String permission)
    {
        this.context = context;
        this.permission = permission;
    }

    /**
     * 无法检查的权限一律返回true
     * 需要在回调返回true时再判断，无法判断的权限有：打电话、发送接收短信、写日历
     * @return
     */
    @Override
    public boolean check()
    {
        try
        {
            switch (permission)
            {
                case Manifest.permission.READ_CONTACTS:
                    return checkReadContacts();
                case Manifest.permission.WRITE_CONTACTS:
                    return checkWriteContacts();
                case Manifest.permission.WRITE_CALL_LOG:
                    return checkWriteCallLog();
                case Manifest.permission.READ_CALL_LOG:
                    return checkReadCallLog();
                case Manifest.permission.CALL_PHONE:
                    return checkCall();
                case Manifest.permission.READ_PHONE_STATE:
                    return checkReadPhoneState();
                case Manifest.permission.CAMERA:
                    return checkCamera();
                case Manifest.permission.READ_EXTERNAL_STORAGE:
                    return checkReadStorage();
                case Manifest.permission.WRITE_EXTERNAL_STORAGE:
                    return checkWriteStorage();
                case Manifest.permission.ACCESS_FINE_LOCATION:
                case Manifest.permission.ACCESS_COARSE_LOCATION:
                    return checkLocation();
                case Manifest.permission.RECORD_AUDIO:
                    return checkRecordAudio();
                case Manifest.permission.BODY_SENSORS:
                    return checkBodySensors();
                case Manifest.permission.READ_CALENDAR:
                    return checkReadCalendar();
                case Manifest.permission.WRITE_CALENDAR:
                    return true;
                case Manifest.permission.READ_SMS:
                    return checkReadSms();
                case Manifest.permission.SEND_SMS:
                case Manifest.permission.RECEIVE_SMS:
                    return true;
                default:
                    return true;
            }
        } catch (Exception e)
        {
            e.printStackTrace();
            return false;
        }
    }

    private boolean checkCall() throws Exception
    {
//        Intent intent = new Intent(Intent.ACTION_CALL);
//        Uri data = Uri.parse("tel:10086");
//        intent.setData(data);
//        Activity ac = PermissionActivityManager.getInstance().getTopActivity();
//        if(ac != null)
//        {
//            ac.startActivity(intent);
//        }
        return false;

//        return new AppOpsChecker(PermissionActivityManager.getInstance().getTopActivity()).checkOp(13);
    }

    private boolean checkReadContacts() throws Exception
    {
        Cursor cursor = context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone
                .CONTENT_URI, null, null, null, null);
        if (cursor != null)
        {
            if (PermissionTools.isForceManufacturer())
            {
                if (isNumberIndexInfoIsNull(cursor, cursor.getColumnIndex(ContactsContract.CommonDataKinds
                        .Phone.NUMBER)))
                {
                    cursor.close();
                    return false;
                }
            }
            cursor.close();
            return true;
        } else
        {
            return false;
        }
    }

    private boolean checkWriteContacts() throws Exception
    {
        if (checkReadContacts())
        {
            // write some info
            ContentValues values = new ContentValues();
            ContentResolver contentResolver = context.getContentResolver();
            Uri rawContactUri = contentResolver.insert(ContactsContract.RawContacts.CONTENT_URI, values);
            long rawContactId = ContentUris.parseId(rawContactUri);
            values.put(ContactsContract.Contacts.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
            values.put(ContactsContract.Contacts.Data.RAW_CONTACT_ID, rawContactId);
            values.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, "touch");
            values.put(ContactsContract.CommonDataKinds.Phone.NUMBER, "1");
            contentResolver.insert(ContactsContract.Data.CONTENT_URI, values);

            // delete info
            Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
            ContentResolver resolver = context.getContentResolver();
            Cursor cursor = resolver.query(uri, new String[]{ContactsContract.Contacts.Data._ID},
                    "display_name=?", new String[]{"touch"}, null);
            if (cursor != null)
            {
                if (cursor.moveToFirst())
                {
                    int id = cursor.getInt(0);
                    resolver.delete(uri, "display_name=?", new String[]{"touch"});
                    uri = Uri.parse("content://com.android.contacts/data");
                    resolver.delete(uri, "raw_contact_id=?", new String[]{id + ""});
                }
                cursor.close();
            }
            return true;
        } else
        {
            return false;
        }
    }

    private boolean checkCamera() throws Exception
    {
        Camera camera = Camera.open();
        camera.release();
        return true;
    }

    private boolean checkReadCallLog() throws Exception
    {
        Cursor cursor = context.getContentResolver().query(Uri.parse("content://call_log/calls"),
                null, null, null, null);
        if (cursor != null)
        {
            if (PermissionTools.isForceManufacturer())
            {
                if (isNumberIndexInfoIsNull(cursor, cursor.getColumnIndex(CallLog.Calls.NUMBER)))
                {
                    cursor.close();
                    return false;
                }
            }
            cursor.close();
            return true;
        } else
        {
            return false;
        }
    }

    @SuppressLint({"HardwareIds", "MissingPermission"})
    private boolean checkReadPhoneState() throws Exception
    {
        TelephonyManager service = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        if (PermissionsPageManager.isMEIZU())
        {
            return !TextUtils.isEmpty(service.getSubscriberId());
        } else if (PermissionsPageManager.isXIAOMI() || PermissionsPageManager.isOPPO())
        {
            return !TextUtils.isEmpty(service.getDeviceId());
        } else
        {
            return !TextUtils.isEmpty(service.getDeviceId()) || !TextUtils.isEmpty(service
                    .getSubscriberId());
        }
    }

    private boolean checkWriteCallLog() throws Exception
    {
        ContentResolver contentResolver = context.getContentResolver();
        ContentValues content = new ContentValues();
        content.put(CallLog.Calls.TYPE, CallLog.Calls.INCOMING_TYPE);
        content.put(CallLog.Calls.NUMBER, "1");
        content.put(CallLog.Calls.DATE, 20140808);
        content.put(CallLog.Calls.NEW, "0");
        contentResolver.insert(Uri.parse("content://call_log/calls"), content);
        contentResolver.delete(Uri.parse("content://call_log/calls"), "number = ?", new String[]{"1"});

        return true;
    }

    private boolean checkReadCalendar() throws Exception
    {
        Cursor cursor = context.getContentResolver()
                .query(Uri.parse("content://com" + ".android.calendar/calendars"),
                        null, null, null, null);
        if (cursor != null)
        {
            cursor.close();
            return true;
        } else
        {
            return false;
        }
    }

    private boolean checkBodySensors() throws Exception
    {
        SensorManager sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
        Sensor sensor = sensorManager.getDefaultSensor((Sensor.TYPE_ACCELEROMETER));
        SensorEventListener listener = new SensorEventListener()
        {
            @Override
            public void onSensorChanged(SensorEvent event)
            {
            }

            @Override
            public void onAccuracyChanged(Sensor sensor, int accuracy)
            {
            }
        };
        sensorManager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_GAME);
        sensorManager.unregisterListener(listener, sensor);

        return true;
    }

    @SuppressLint("MissingPermission")
    private boolean checkLocation() throws Exception
    {
        granted = false;
        isLocationRetured = false;

        final LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
        List<String> list = locationManager.getProviders(true);

        if (list.contains(LocationManager.GPS_PROVIDER))
        {
            return true;
        } else if (list.contains(LocationManager.NETWORK_PROVIDER))
        {
            return true;
        } else
        {
            if (!locationManager.isProviderEnabled("gps"))
            {
                locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0L, 0F, new
                        LocationListener()
                        {
                            @Override
                            public void onLocationChanged(Location location)
                            {
                                locationManager.removeUpdates(this);
                                isLocationRetured = true;
                            }

                            @Override
                            public void onStatusChanged(String provider, int status, Bundle extras)
                            {
                                locationManager.removeUpdates(this);
                                granted = true;
                                isLocationRetured = true;
                            }

                            @Override
                            public void onProviderEnabled(String provider)
                            {
                                locationManager.removeUpdates(this);
                                isLocationRetured = true;
                            }

                            @Override
                            public void onProviderDisabled(String provider)
                            {
                                locationManager.removeUpdates(this);
                                isLocationRetured = true;
                            }
                        });
                while (!isLocationRetured)
                {
                    SystemClock.sleep(50);
                }
            }
            return granted;
        }
    }

    private boolean checkReadStorage() throws Exception
    {
        File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getPath());
        File[] files = file.listFiles();
        return files != null;
    }

    private boolean checkWriteStorage() throws Exception
    {
        File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getPath(), "touch");
        if (!file.exists())
        {
            boolean newFile;
            try
            {
                newFile = file.createNewFile();
            } catch (IOException e)
            {
                e.printStackTrace();
                return false;
            }
            return newFile;
        } else
        {
            return file.delete();
        }
    }

    private boolean checkRecordAudio() throws Exception
    {
        MediaRecorder recorder = new MediaRecorder();
        recorder.setAudioChannels(1);
        recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
        recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
        recorder.setOutputFile(new File(context.getCacheDir(), "/touch.3gp").getAbsolutePath());
        recorder.prepare();
        recorder.release();

        return true;
    }

    private boolean checkReadSms() throws Exception
    {
        Cursor cursor = context.getContentResolver().query(Uri.parse("content://sms/"), null, null,
                null, null);
        if (cursor != null)
        {
            if (PermissionTools.isForceManufacturer())
            {
                if (isNumberIndexInfoIsNull(cursor, cursor.getColumnIndex(Telephony.Sms.DATE)))
                {
                    cursor.close();
                    return false;
                }
            }
            cursor.close();
            return true;
        } else
        {
            return false;
        }
    }

    private boolean isNumberIndexInfoIsNull(Cursor cursor, int numberIndex)
    {
        if (cursor.getCount() > 0)
        {
            while (cursor.moveToNext())
            {
                return TextUtils.isEmpty(cursor.getString(numberIndex));
            }
            return false;
        } else
        {
            return true;
        }
    }
}
